package com.msi;

import org.simpleframework.xml.Element;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Vertex {

    /**
     * liczba całkowita reprezentujca kolor wierchołka wartość -1 oznacza, że
     * wiercho�ek nie zosta� jeszcze pokolorwany
     */
    @Element
    private int color = -1;
    /**
     * stopie� wiercho�ka
     */
    @Element
    private int degree;
    /**
     * ID wierzcho�ka (warto�ci od zera)
     */
    @Element
    private int id;
    /**
     * list� s�siedztwa precyzuj�ca kraw�dzie przylegaj�ce do bie��cego
     * wiercho�ka
     */
    List<Vertex> neighbourhood = new ArrayList<Vertex>();
    /**
     * wsp�rz�dna X wierxcho�ka warto�� -1 oznacza, �e wsp�rz�dne nie zosta�y
     * sprecyzowane, a co za tym idzie graf zostanie wy�wietlony przy u�yciu
     * mechanizmu autolayautu
     */
    @Element
    private double x = -1;

    /**
     * wsp�rz�dna Y wierzcho�ka warto�� -1 oznacza, �e wsp�rz�dne nie zosta�y
     * sprecyzowane, a co za tym idzie graf zostanie wy�wietlony przy u�yciu
     * mechanizmu autolayautu
     */
    @Element
    private double y = -1;

    private boolean visited = false;

    private boolean excluded = false;

    public Vertex(int i) {
        this.id = i;
        degree = 0;
    }

    /**
     * @param v
     *            wiercho�ek s�siaduj�cy
     */
    public void addNeighbour(Vertex v) {
        addNeighbourOneWay(v);
        v.addNeighbourOneWay(this);
    }

    public void addNeighbourOneWay(Vertex vertex) {
        neighbourhood.add(vertex);
        ++degree;
    }

    public Vertex createVertexCopyWithoutNeighbors() {
        Vertex result = new Vertex(id);
        result.setColor(color);
        result.setX(x);
        result.setY(y);
        if (visited)
            result.markAsVisited();

        return result;
    }

    private List<Vertex> createSortedVericesList() {

        sortVerticesById(neighbourhood);
        return neighbourhood;

    }

    public int getColor() {
        return color;
    }

    public int getDegree() {
        return degree;
    }

    public int getId() {
        return id;
    }

    public double getY() {
        return y;
    }

    public double getX() {
        return x;
    }

    public List<Vertex> getNeighborhood() {
        return neighbourhood;
    }

    public void print() {
        List<Vertex> verticesList = createSortedVericesList();
        System.out.print("vertex id=" + getId() + " degree=" + degree
                + "  color=" + color + "  -> ");
        for (Vertex v : verticesList) {
            System.out.print(" '" + v.getId());
        }
    }

    public void resetColor() {
        color = -1;
    }

    public void setColor(int c) {
        color = c;
    }

    public void setY(double y) {
        this.y = y;
    }

    public void setX(double x) {
        this.x = x;
    }

    private void sortVerticesById(List<Vertex> verticesList) {
        Collections.sort(verticesList, new Comparator<Vertex>() {

            @Override
            public int compare(Vertex o1, Vertex o2) {
                int id1 = o1.getId();
                int id2 = o2.getId();
                if (id1 < id2)
                    return -1;
                if (id1 > id2)
                    return 1;
                return 0;
            }

        });
    }

    /**
     * Oznacza wierzchołek jako odwiedzony
     */
    public void markAsVisited() {
        visited = true;
    }

    /**
     * Zwraca informację czy wierzchołek został już odwiedzony
     * 
     * @return informacja czy wierzchołek został już odwiedzony
     */
    public boolean isVisited() {
        return visited;
    }

    /**
     * Oznacza wierzchołek jako wyłączony z grafu
     */
    public void exclude() {
        this.excluded = true;
        // kazdemu sąsiadowi zmniejszamy stopień - ten wierzchołek już się nie
        // wlicza
        for (Vertex neighbour : neighbourhood) {
            --neighbour.degree;
        }
    }

    /**
     * Zwraca informację, czy wierzchołek jest wyłączony z grafu
     * 
     * @return informacja, czy wierzchołek jest wyłączony z grafu
     */
    public boolean isExcluded() {
        return this.excluded;
    }

    @Override
    public boolean equals(Object obj) {
        Vertex v = (Vertex) obj;
        return id == v.id;
    }

    @Override
    public int hashCode() {
        // TODO
        return super.hashCode();
    }
}
